package com.google.code.hibernate.rest.method;

import static com.google.code.hibernate.rest.method.Methods.DELETE;
import static com.google.code.hibernate.rest.method.Methods.GET;
import static com.google.code.hibernate.rest.method.Methods.HEAD;
import static com.google.code.hibernate.rest.method.Methods.OPTIONS;
import static com.google.code.hibernate.rest.method.Methods.POST;
import static com.google.code.hibernate.rest.method.Methods.PUT;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import com.google.code.hibernate.rest.EntityManager;
import com.google.code.hibernate.rest.EntityNotFoundException;

/**
 * 
 * @author wangzijian
 * 
 */
enum URIMatchMode {

	Root {
		@Override
		public List<String> getAllowMethods(String uri, EntityManager entityManager) {
			return Arrays.asList(GET, HEAD, OPTIONS);
		}

	},
	EntityRoot(new URITemplate("/{entityName}")) {
		@Override
		public List<String> getAllowMethods(String uri, EntityManager entityManager) {
			String entityName = uri.substring(1);
			if (!entityManager.getSimpleEntityNames().containsKey(entityName)) {
				throw new EntityNotFoundException(entityName);
			}
			return Arrays.asList(GET, HEAD, OPTIONS, POST);
		}

	},
	Entity(new URITemplate("/{entityName}/{id}")) {

		@Override
		public List<String> getAllowMethods(String uri, EntityManager entityManager) {
			Map<String, String> variables = template().match(uri);
			String entityName = variables.get("entityName");
			String id = variables.get("id");
			if (!entityManager.exists(entityName, id)) {
				throw new EntityNotFoundException(entityName);
			}
			if (entityManager.isMutable(entityName)) {
				return Arrays.asList(GET, HEAD, OPTIONS, PUT, DELETE);
			} else {
				return Arrays.asList(GET, HEAD, OPTIONS);
			}
		}

	};

	private final URITemplate template;

	public abstract List<String> getAllowMethods(String uri, EntityManager entityManager);

	private URIMatchMode() {
		this(null);
	}

	private URIMatchMode(URITemplate uriTemplate) {
		this.template = uriTemplate;
	}

	public URITemplate template() {
		return template;
	}

	public static URIMatchMode matchs(String uri) {
		if (uri == null) {
			return Root;
		} else if (Entity.template.matches(uri)) {
			return Entity;
		} else if (EntityRoot.template.matches(uri)) {
			return EntityRoot;
		} else {
			throw new URINotMatchedException(uri);
		}
	}

}
